home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / POVHELP.ZIP / source / phe2txt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-20  |  27.4 KB  |  1,102 lines

  1.  
  2.  
  3. /****************************************************************************
  4. *                   PHE2TXT.C - version 1.0
  5. *
  6. *  This module implements the POV-Help database to Plain ASCII Text converter.
  7. *
  8. *  from Persistence of Vision Raytracer
  9. *  Copyright 1994 Persistence of Vision Team
  10. *  Copyright 1994 Christopher J. Cason.
  11. *---------------------------------------------------------------------------
  12. *  NOTICE: This source code file is provided so that users may experiment
  13. *  with enhancements to POV-Ray and to port the software to platforms other
  14. *  than those supported by the POV-Ray Team.  There are strict rules under
  15. *  which you are permitted to use this file.  The rules are in the file
  16. *  named POVLEGAL.DOC which should be distributed with this file. If
  17. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  18. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  19. *  Forum.  The latest version of POV-Ray may be found there as well.
  20. *
  21. *  POV-Ray files may also be obtained from ftp.uwa.edu.au in pub/povray.
  22. *
  23. *  This program was written in its entirety by Christopher J. Cason.
  24. *  Its use is freely and permanently granted to the POV-Team and POV users
  25. *  under the conditions specified in POVLEGAL.DOC.
  26. *
  27. *  Author : C. J. Cason (cjcason@yarrow.wt.uwa.edu.au, CIS 100032,1644)
  28. *
  29. *****************************************************************************/
  30.  
  31. /*---------------------------------------------------------------------------*/
  32. /* NOTE : If you're porting this to another architecture, don't forget that  */
  33. /*        the POV-Help database stores words and dwords in LSB-first format. */
  34. /*---------------------------------------------------------------------------*/
  35.  
  36. #include <stdio.h>
  37. #include <mem.h>
  38. #include <string.h>
  39. #include <alloc.h>
  40. #include <stdlib.h>
  41. #include <conio.h>
  42. #include <dos.h>
  43. #include <bios.h>
  44. #include <ctype.h>
  45. #include "help.h"
  46.  
  47. typedef unsigned char   uchar ;
  48.  
  49. #define MAX_REF         512
  50. #define MAX_FRAGMENT    16
  51. #define MAX_LINK        64
  52. #define VSIZE_Y         128
  53. #define VSIZE_X         128
  54.  
  55. #define TITLE           0x01
  56. #define COPYRIGHT       0x02
  57. #define AUTHOR          0x03
  58. #define FAQ             0x04
  59. #define CONTENTS        0x100
  60.  
  61. #define PRESERVE        (preserve_formatting || code_fragment || line_drawing)
  62.  
  63. #ifdef max
  64. #undef max
  65. #endif
  66.  
  67. #ifdef min
  68. #undef min
  69. #endif
  70.  
  71. #define max(a,b)        ((int) (a) > (int) (b) ? (a) : (b))
  72. #define min(a,b)        ((int) (a) < (int) (b) ? (a) : (b))
  73.  
  74. typedef struct
  75. {
  76.   unsigned char         start_vx ;
  77.   unsigned char         end_vx ;
  78.   unsigned short        id ;
  79.   unsigned short        start_vy ;
  80.   unsigned short        end_vy ;
  81. } viewer_reference ;
  82.  
  83. typedef struct
  84. {
  85.   unsigned char         start_vx ;
  86.   unsigned char         end_vx ;
  87.   unsigned short        start_vy ;
  88.   unsigned short        end_vy ;
  89. } viewer_code_fragment ;
  90.  
  91. typedef struct
  92. {
  93.   /* these first three entries must not be changed/moved */
  94.   unsigned long         section ;
  95.   unsigned long         section_length ;
  96.   unsigned char         is_appendix ;
  97.   unsigned char         number [16] ;
  98.   unsigned char         title [80] ;
  99.   unsigned              index ;
  100. } viewer_toc ;
  101.  
  102. uchar                   *title ;
  103. uchar                   blank [VSIZE_X] ;
  104. uchar                   *reference_strings ;
  105. uchar                   **reference_string_index ;
  106. void far                *pageframe ;
  107. short                   first_line = 0 ;
  108. short                   wsize_y = 15 ;
  109. unsigned char           attribute ;
  110. unsigned char           reference ;
  111. unsigned char           highlight ;
  112. unsigned char           bold ;
  113. unsigned char           code_fragment ;
  114. unsigned char           heading ;
  115. unsigned char           line_drawing ;
  116. unsigned char           preserve_formatting ;
  117. unsigned char           table ;
  118. unsigned char           list ;
  119. unsigned char           list_entry ;
  120. unsigned char           vx ;
  121. unsigned char           wsize_x = 77 ;
  122. unsigned char           left_margin ;
  123. unsigned char           right_margin ;
  124. unsigned char           (*page_buffer) [VSIZE_Y] [VSIZE_X] ;
  125. unsigned char           (*attribute_buffer) [VSIZE_Y] [VSIZE_X] ;
  126. unsigned char           *toc ;
  127. unsigned char           *section ;
  128. unsigned long           links [MAX_LINK] ;
  129. unsigned long           *reference_index ;
  130. unsigned short          vy ;
  131. unsigned short          reference_count ;
  132. unsigned short          code_fragment_count ;
  133. unsigned short          TOCsize ;
  134. unsigned short          ignore_lines = 0 ;
  135. unsigned short          link_count ;
  136. unsigned short          target_line ;
  137. unsigned short          noFAQ = 1 ;
  138. unsigned short          justifyOn = 1 ;
  139. FILE                    *inF ;
  140. FILE                    *outF ;
  141. viewer_toc              tc ;
  142. viewer_reference        *references ;
  143. viewer_code_fragment    *code_fragments ;
  144. help_file_header        header ;
  145.  
  146. unsigned astrlen (char *s, unsigned width)
  147. {
  148.   char        *s1 = s + width ;
  149.  
  150.   while (*--s1 == ' ' && s1 > s) ;
  151.   return ((unsigned) (s1 - s)) ;
  152. }
  153.  
  154. unsigned wordcount (char *s, unsigned width)
  155. {
  156.   unsigned    wc = 0 ;
  157.   unsigned    inword = 0 ;
  158.  
  159.   while (width--)
  160.   {
  161.     if (inword == 0)
  162.     {
  163.       if (*s++ == ' ') continue ;
  164.       inword++ ;
  165.       wc++ ;
  166.     }
  167.     else
  168.     {
  169.       if (*s++ != ' ') continue ;
  170.       inword = 0 ;
  171.     }
  172.   }
  173.   return (wc) ;
  174. }
  175.  
  176. void insertspaces (unsigned howmany, char *s, unsigned width)
  177. {
  178.   char        *s1 = s + width ;
  179.  
  180.   while (howmany--)
  181.   {
  182.     while (*--s1 == ' ' && s1 > s) ;
  183.     if (s1 == s) return ;
  184.     while (*--s1 != ' ' && s1 > s) ;
  185.     if (s1 == s) return ;
  186.     memmove (s1 + 1, s1, (width - (unsigned) (s1 - s) - 1)) ;
  187.   }
  188. }
  189.  
  190. void justify (char *s, unsigned width)
  191. {
  192.   int         needed ;
  193.   unsigned    wc ;
  194.  
  195.   if ((needed = width - astrlen (s, width) - 1) <= 0) return ;
  196.   if ((wc = wordcount (s, width)) == 0) return ;
  197.   while (needed > wc)
  198.   {
  199.     insertspaces (needed, s, width) ;
  200.     needed -= wc ;
  201.   }
  202.   insertspaces (needed, s, width) ;
  203. }
  204.  
  205. unsigned ustrcmp (char *s1, char *s2)
  206. {
  207.   while (*s1 && *s2)
  208.     if (toupper (*s1++) != toupper (*s2++))
  209.       return (1) ;
  210.   return (*s1 || *s2) ;
  211. }
  212.  
  213. unsigned page_buffer_full (void)
  214. {
  215.   return (vy >= VSIZE_Y - 1) ;
  216. }
  217.  
  218. void clear_page_buffer (void)
  219. {
  220.   vx = 0 ;
  221.   vy = 0 ;
  222.   left_margin = 0 ;
  223.   right_margin = wsize_x ;
  224.   memset (page_buffer, ' ', VSIZE_X * VSIZE_Y) ;
  225.   memset (attribute_buffer, 0, VSIZE_X * VSIZE_Y) ;
  226. }
  227.  
  228. unsigned line_is_blank (unsigned line)
  229. {
  230.   uchar       *s = (*page_buffer) [line] ;
  231.   unsigned    count = VSIZE_X ;
  232.  
  233.   while (count--)
  234.     if (*--s != ' ')
  235.       return (0) ;
  236.   return (1) ;
  237. }
  238.  
  239. char *trim (char *line)
  240. {
  241.   char        *s ;
  242.  
  243.   s = line + VSIZE_X - 1 ;
  244.   while (s >= line && *s == ' ') s-- ;
  245.   *++s = '\0' ;
  246.   return (line) ;
  247. }
  248.  
  249. /* in device_setup, do whatever setup is needed for your output medium */
  250.  
  251. void device_setup (void)
  252. {
  253. }
  254.  
  255. unsigned process_page (void)
  256. {
  257.   int         i ;
  258.  
  259.   for (i = 0 ; i <= vy ; i++)
  260.     fprintf (outF, "%.*s\n", wsize_x, trim ((*page_buffer) [i])) ;
  261.   clear_page_buffer () ;
  262.   return (0) ;
  263. }
  264.  
  265. void process_section (void)
  266. {
  267.   fprintf (outF, "\n") ;
  268. }
  269.  
  270. void write_attribute (int x1, int y1, int x2, int y2, char attr)
  271. {
  272.   unsigned    count = (y2 * VSIZE_X + x2) - (y1 * VSIZE_X + x1) ;
  273.  
  274.   if (y2 < y1) return ;
  275.   if (y2 == y1 && x2 < x1) return ;
  276.   memset (attribute_buffer [y1] + x1, attr, count) ;
  277. }
  278.  
  279. void clear_attributes (void)
  280. {
  281.   reference = highlight = bold = code_fragment = 0 ;
  282.   heading = line_drawing = preserve_formatting = 0 ;
  283.   table = list = list_entry = 0 ;
  284. }
  285.  
  286. void set_attribute (void)
  287. {
  288.   attribute = 0 ;
  289.   if (code_fragment) attribute |= CODE_FRAGMENT ;
  290.   if (heading) attribute |= HEADING ;
  291.   if (line_drawing) attribute |= LINE_DRAWING ;
  292.   if (list_entry) attribute |= LIST_ENTRY ;
  293.   if (bold) attribute |= BOLD ;
  294.   if (highlight) attribute |= HIGHLIGHT ;
  295.   if (reference) attribute |= REF ;
  296. }
  297.  
  298. viewer_reference *create_reference (unsigned short id)
  299. {
  300.   if (reference_count == MAX_REF) return (NULL) ;
  301.   references [reference_count].id = id ;
  302.   return (references + reference_count++) ;
  303. }
  304.  
  305. void clear_references (void)
  306. {
  307.   reference_count = 0 ;
  308. }
  309.  
  310. viewer_code_fragment *create_code_fragment (void)
  311. {
  312.   if (code_fragment_count == MAX_FRAGMENT) return (NULL) ;
  313.   return (code_fragments + code_fragment_count++) ;
  314. }
  315.  
  316. void clear_code_fragments (void)
  317. {
  318.   code_fragment_count = 0 ;
  319. }
  320.  
  321. viewer_toc *getTC (unsigned index)
  322. {
  323.   uchar                 *s ;
  324.   static viewer_toc     result ;
  325.  
  326.   if (index >= header.section_count + header.appendix_count) index = 0 ;
  327.   s = toc + (unsigned) ((unsigned long) TOCsize * index) ;
  328.   memcpy (&result, s, sizeof (TOC_entry)) ;
  329.   s += sizeof (TOC_entry) ;
  330.   strcpy (result.number, s) ;
  331.   strcpy (result.title, s + header.sec_number_len) ;
  332.   result.index = index ;
  333.   return (&result) ;
  334. }
  335.  
  336. viewer_toc *findTCfromOffset (unsigned long offset)
  337. {
  338.   unsigned              i ;
  339.   static viewer_toc     result ;
  340.  
  341.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  342.   {
  343.     result = *getTC (i) ;
  344.     if (result.section > offset) continue ;
  345.     if (result.section + result.section_length <= offset) continue ;
  346.     return (&result) ;
  347.   }
  348.   return (NULL) ;
  349. }
  350.  
  351. char *get_section (viewer_toc *tc, unsigned number)
  352. {
  353.   uchar       *section ;
  354.   unsigned    count ;
  355.  
  356.   *tc = *getTC (number) ;
  357.   fseek (inF, tc->section, SEEK_SET) ;
  358.   if (tc->section_length + 1 > 65534U)
  359.   {
  360.     printf ("section too big for present allocation code") ;
  361.     return (NULL) ;
  362.   }
  363.   if ((section = calloc ((unsigned) tc->section_length + 1, 1)) == NULL)
  364.   {
  365.     printf ("error - cannot allocate enough memory for section %s", tc->number) ;
  366.     return (NULL) ;
  367.   }
  368.   if (fread (section, (unsigned) tc->section_length + 1, 1, inF) == 0)
  369.   {
  370.     printf ("could not read section") ;
  371.     return (NULL) ;
  372.   }
  373.   count = (unsigned) tc->section_length ;
  374.   while (section [count - 1] == '\n' || section [count - 1] == PARAGRAPH) count-- ;
  375.   section [count] = '\0' ;
  376.   return (section) ;
  377. }
  378.  
  379. unsigned findSection (char *s)
  380. {
  381.   unsigned              i ;
  382.   viewer_toc            result ;
  383.  
  384.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  385.   {
  386.     result = *getTC (i) ;
  387.     if (ustrcmp (s, result.number)) continue ;
  388.     return (i) ;
  389.   }
  390.   return (-1) ;
  391. }
  392.  
  393. unsigned findTitle (char *s)
  394. {
  395.   static char           str [80] ;
  396.   unsigned              i ;
  397.   viewer_toc            result ;
  398.  
  399.   strupr (s) ;
  400.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  401.   {
  402.     result = *getTC (i) ;
  403.     if (ustrcmp (s, result.title)) continue ;
  404.     return (i) ;
  405.   }
  406.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  407.   {
  408.     result = *getTC (i) ;
  409.     strcpy (str, result.title) ;
  410.     strupr (str) ;
  411.     if (strstr (str, s) == NULL) continue ;
  412.     return (i) ;
  413.   }
  414.   return (-1) ;
  415. }
  416.  
  417. void vputchar (unsigned char ch)
  418. {
  419.   if (vy >= VSIZE_Y) return ;
  420.  
  421.   switch (ch)
  422.   {
  423.     case '\r' :
  424.          vx = 0 ;
  425.          return ;
  426.  
  427.     case '\n' :
  428.          vx = VSIZE_X ;
  429.          break ;
  430.  
  431.     default :
  432.          if (vx >= VSIZE_X) return ;
  433.          if (ignore_lines) break ;
  434.          (*page_buffer) [vy] [vx] = ch ;
  435.          (*attribute_buffer) [vy] [vx] = attribute ;
  436.          break ;
  437.   }
  438.  
  439.   if (++vx >= VSIZE_X)
  440.   {
  441.     if (ch == '\n' || !PRESERVE)
  442.     {
  443.       vx = left_margin ;
  444.       if (ignore_lines)
  445.       {
  446.         --ignore_lines ;
  447.         return ;
  448.       }
  449.       if (++vy >= VSIZE_Y) vy = VSIZE_Y ;
  450.     }
  451.   }
  452. }
  453.  
  454. void vputchar_attr (unsigned char ch, unsigned char attr)
  455. {
  456.   unsigned char         a = attribute ;
  457.  
  458.   attribute = attr ;
  459.   vputchar (ch) ;
  460.   attribute = a ;
  461. }
  462.  
  463. void vputstr (char *s)
  464. {
  465.   while (*s)
  466.     vputchar (*s++) ;
  467. }
  468.  
  469. void cvputstr (char *s)
  470. {
  471.   static char str [256] ;
  472.   char        *s1 = str ;
  473.   unsigned    count ;
  474.  
  475.   for (count = 0 ;; s++)
  476.   {
  477.     if (page_buffer_full ())
  478.       if (process_page ())
  479.         break ;
  480.  
  481.     if (*s == '\n' || *s == '\0')
  482.     {
  483.       vx = (wsize_x - count) / 2 ;
  484.       if (vx < 0) vx = 0 ;
  485.       for (s1 = str ; count ; count--)
  486.         vputchar (*s1++) ;
  487.       vputchar ('\n') ;
  488.       if (*s == '\0') break ;
  489.       s1 = str ;
  490.       continue ;
  491.     }
  492.     *s1++ = *s ;
  493.     count++ ;
  494.   }
  495. }
  496.  
  497. unsigned pointcount (char *s)
  498. {
  499.   unsigned    count = 0 ;
  500.  
  501.   while (*s)
  502.     if (*s++ == '.')
  503.       count++ ;
  504.   return (count) ;
  505. }
  506.  
  507. void vcachechar (char ch)
  508. {
  509.   char                  *s ;
  510.   static char           str [128] ;
  511.   static unsigned       count = 0 ;
  512.  
  513.   if (ch == '\0' || ch == ' ' || ch == '\t' || ch == '\n' || count == 128)
  514.   {
  515.     if (count / 2 > right_margin - vx)
  516.     {
  517.       if (justifyOn)
  518.         justify ((char *) ((*page_buffer) [vy]), wsize_x) ;
  519.       vputchar ('\n') ;
  520.     }
  521.     for (s = str ; count ; count -= 2, s += 2)
  522.       if (*s != ' ' || vx != left_margin)
  523.         vputchar_attr (s [0], s [1]) ;
  524.     if (ch == '\0') return ;
  525.   }
  526.   if (PRESERVE)
  527.   {
  528.     vputchar (ch) ;
  529.     return ;
  530.   }
  531.   str [count++] = ch ;
  532.   str [count++] = attribute ;
  533. }
  534.  
  535. void format_section (viewer_toc *tc, unsigned char *section)
  536. {
  537.   unsigned              id ;
  538.   unsigned              escape = 0 ;
  539.   unsigned char         *s ;
  540.   viewer_reference      *r ;
  541.   viewer_code_fragment  *f ;
  542.  
  543.   clear_attributes () ;
  544.   set_attribute () ;
  545.   clear_references () ;
  546.   clear_code_fragments () ;
  547.   clear_page_buffer () ;
  548.   ignore_lines = first_line ;
  549.   target_line = 0 ;
  550.   if (tc)
  551.   {
  552.     heading++ ;
  553.     set_attribute () ;
  554.     if (tc->is_appendix) vputstr ("APPENDIX ") ;
  555.     vputstr (tc->number) ;
  556.     vx = 17 ;
  557.     vputstr (tc->title) ;
  558.     heading = 0 ;
  559.     vcachechar ('\n') ;
  560.     vcachechar ('\n') ;
  561.     set_attribute () ;
  562.   }
  563.  
  564.   while (*section == '\n' || *section == PARAGRAPH) section++ ;
  565.  
  566.   for (s = section ; *s ; s++)
  567.   {
  568.     if (page_buffer_full ())
  569.       if (process_page ())
  570.         break ;
  571.  
  572.     if (escape == 0)
  573.     {
  574.       switch (*s)
  575.       {
  576.         case ESCAPE :
  577.              escape++ ;
  578.              break ;
  579.  
  580.         case PARAGRAPH :
  581.              vcachechar ('\n') ;
  582.              vcachechar ('\n') ;
  583.              break ;
  584.  
  585.         case INDENT :
  586.              vx = 3 ;
  587.              break ;
  588.  
  589.         case REFERENCE :
  590.              id = *++s ;
  591.              id += (unsigned) *++s * 256 ;
  592.              r = create_reference (id) ;
  593.              break ;
  594.  
  595.         case TARGET :
  596.              break ;
  597.  
  598.         case REFERENCE_ON :
  599.              if (r == NULL) break ;
  600.              vcachechar ('\0') ;
  601.              r->start_vx = vx ;
  602.              r->start_vy = vy ;
  603.              reference++ ;
  604.              set_attribute () ;
  605.              break ;
  606.  
  607.         case REFERENCE_OFF :
  608.              if (r == NULL) break ;
  609.              vcachechar ('\0') ;
  610.              r->end_vx = vx ;
  611.              r->end_vy = vy ;
  612.              reference = 0 ;
  613.              r = NULL ;
  614.              set_attribute () ;
  615.              break ;
  616.  
  617.         case HIGHLIGHT_ON :
  618.         case HIGHLIGHT_OFF :
  619.              highlight = *s == HIGHLIGHT_ON ;
  620.              set_attribute () ;
  621.              break ;
  622.  
  623.         case BOLD_ON :
  624.         case BOLD_OFF :
  625.              bold = *s == BOLD_ON ;
  626.              set_attribute () ;
  627.              break ;
  628.  
  629.         case CODE_ON :
  630.              code_fragment++ ;
  631.              set_attribute () ;
  632.              vcachechar ('\0') ;
  633.              if ((f = create_code_fragment ()) == NULL) break ;
  634.              f->start_vx = vx ;
  635.              f->start_vy = vy ;
  636.              break ;
  637.  
  638.         case CODE_OFF :
  639.              code_fragment = 0 ;
  640.              set_attribute () ;
  641.              vcachechar ('\0') ;
  642.              if (f == NULL) break ;
  643.              f->end_vx = vx ;
  644.              f->end_vy = vy ;
  645.              f = NULL ;
  646.              break ;
  647.  
  648.         case HEADING_ON :
  649.         case HEADING_OFF :
  650.              heading = *s == HEADING_ON ;
  651.              set_attribute () ;
  652.              break ;
  653.  
  654.         case LINE_ON :
  655.         case LINE_OFF :
  656.              line_drawing = *s == LINE_ON ;
  657.              set_attribute () ;
  658.              vcachechar ('\0') ;
  659.              break ;
  660.  
  661.         case PRESERVE_ON :
  662.         case PRESERVE_OFF :
  663.              preserve_formatting = *s == PRESERVE_ON ;
  664.              set_attribute () ;
  665.              vcachechar ('\0') ;
  666.              break ;
  667.  
  668.         case TABLE_ON :
  669.         case TABLE_OFF :
  670.              table = *s == TABLE_ON ;
  671.              set_attribute () ;
  672.              break ;
  673.  
  674.         case LIST_ON :
  675.              if ((list = *++s) == 1) list++ ;
  676.              left_margin = list += 2 ;
  677.              break ;
  678.  
  679.         case LIST_OFF :
  680.              left_margin = list = 0 ;
  681.              break ;
  682.  
  683.         case LIST_ENTRY_ON :
  684.              list_entry++ ;
  685.              vcachechar ('\0') ;
  686.              set_attribute () ;
  687.              vx = 2 ;
  688.              break ;
  689.  
  690.         case LIST_ENTRY_OFF :
  691.              list_entry = 0 ;
  692.              vcachechar ('\0') ;
  693.              set_attribute () ;
  694.              vx = left_margin ;
  695.              while (*s == ' ') s++ ;
  696.              break ;
  697.  
  698.         default :
  699.              vcachechar (*s) ;
  700.              break ;
  701.       }
  702.     }
  703.     else
  704.     {
  705.       vcachechar (*s) ;
  706.       escape = 0 ;
  707.     }
  708.   }
  709.   vcachechar ('\0') ;
  710.   while (vy > 0 && line_is_blank (vy)) vy-- ;
  711.   if (reference)
  712.   {
  713.     reference_count-- ;
  714.     reference = 0 ;
  715.   }
  716.   process_page () ;
  717.   process_section () ;
  718. }
  719.  
  720. void format_authors (char *s)
  721. {
  722.   clear_attributes () ;
  723.   set_attribute () ;
  724.   clear_references () ;
  725.   clear_page_buffer () ;
  726.   ignore_lines = first_line ;
  727.   target_line = 0 ;
  728.  
  729.   cvputstr ("AUTHORS\r\n") ;
  730.  
  731.   cvputstr (s) ;
  732.   while (vy > 0 && line_is_blank (vy)) vy-- ;
  733. }
  734.  
  735. void load_links (void)
  736. {
  737.   unsigned    child_count ;
  738.  
  739.   link_count = 0 ;
  740.   fseek (inF, reference_index [references [0].id], SEEK_SET) ;
  741.   fread (&child_count, 2, 1, inF) ;
  742.   if (child_count >= MAX_LINK - 1) child_count = MAX_LINK - 1 ;
  743.   fread (links, 4, link_count = child_count + 1, inF) ;
  744. }
  745.  
  746. void display_text (unsigned what)
  747. {
  748.   char                  *text ;
  749.   char                  *s ;
  750.   unsigned              i ;
  751.   unsigned long         offset ;
  752.   unsigned long         length ;
  753.  
  754.   switch (what)
  755.   {
  756.     case COPYRIGHT :
  757.          offset = header.copyright ;
  758.          length = header.copyright_length ;
  759.          break ;
  760.  
  761.     case AUTHOR :
  762.          offset = header.authors ;
  763.          length = header.author_length ;
  764.          break ;
  765.  
  766.     default :
  767.          return ;
  768.   }
  769.  
  770.   first_line = 0 ;
  771.  
  772.   if (length > 65534U)
  773.   {
  774.     printf ("section too big for present allocation code\r\n") ;
  775.     return ;
  776.   }
  777.   if ((text = calloc ((unsigned) length + 1, 1)) == NULL)
  778.   {
  779.     printf ("cannot allocate memory for text\r\n") ;
  780.     return ;
  781.   }
  782.   fseek (inF, offset, SEEK_SET) ;
  783.   if (fread (text, (unsigned) length + 1, 1, inF) == 0)
  784.   {
  785.     printf ("could not read text\r\n") ;
  786.     free (text) ;
  787.     return ;
  788.   }
  789.   text [(unsigned) length] = 0 ;
  790.  
  791.   for (s = text, i = (unsigned) length ; i ; i--, s++)
  792.     if (*s == '\0')
  793.       *s = '\n' ;
  794.  
  795.   if (what == AUTHOR)
  796.     format_authors (text) ;
  797.   else
  798.     format_section (NULL, text) ;
  799.  
  800.   free (text) ;
  801.   process_page () ;
  802.   process_section () ;
  803. }
  804.  
  805. void display_contents (void)
  806. {
  807.   unsigned              i ;
  808.   unsigned              offset ;
  809.   viewer_toc            tc ;
  810.  
  811.   clear_attributes () ;
  812.   set_attribute () ;
  813.   clear_references () ;
  814.   clear_page_buffer () ;
  815.  
  816.   vputstr ("\r\n") ;
  817.   attribute = 0 ;
  818.   cvputstr (title) ;
  819.   vputstr ("\r\n") ;
  820.  
  821.   for (i = 0 ; i < header.section_count + header.appendix_count ; i++)
  822.   {
  823.     if (page_buffer_full ())
  824.       if (process_page ())
  825.         break ;
  826.  
  827.     if (i == header.section_count)
  828.     {
  829.       vputstr ("\r\n") ;
  830.       cvputstr ("*** APPENDICES ***") ;
  831.       vputstr ("\r\n") ;
  832.     }
  833.     tc = *getTC (i) ;
  834.     if (noFAQ && strstr (tc.title, "FREQUENTLY ASKED QUESTIONS") != NULL) break ;
  835.     offset = pointcount (tc.number) * 3 ;
  836.     vx = offset ;
  837.     vputstr (tc.number) ;
  838.     vx = 17 + offset ;
  839.     vputstr (tc.title) ;
  840.     vputstr ("\r\n") ;
  841.   }
  842.   while (vy > 0 && line_is_blank (vy)) vy-- ;
  843.   process_page () ;
  844.   process_section () ;
  845. }
  846.  
  847. unsigned load_strings (void)
  848. {
  849.   char        *s ;
  850.   char        str [81] ;
  851.   unsigned    i ;
  852.   unsigned    count ;
  853.  
  854.   if ((reference_strings = farcalloc ((unsigned) header.reference_string_length, 1)) == NULL) return (1) ;
  855.   if ((reference_string_index = farcalloc (header.reference_count * 4, 1)) == NULL) return (1) ;
  856.   s = reference_strings ;
  857.   for (i = 0 ; i < header.reference_count ; i++)
  858.   {
  859.     fseek (inF, reference_index [i], SEEK_SET) ;
  860.     fread (&count, 2, 1, inF) ;
  861.     fseek (inF, (count + 1) * 4, SEEK_CUR) ;
  862.     if (fgets (str, 80, inF) == NULL) break ;
  863.     strcpy (s, str) ;
  864.     reference_string_index [i] = s ;
  865.     s += strlen (str) + 1 ;
  866.   }
  867.   return (0) ;
  868. }
  869.  
  870. void init (void)
  871. {
  872.   if ((references = calloc (sizeof (viewer_reference), MAX_REF)) == NULL)
  873.   {
  874.     printf ("cannot allocate memory for references\r\n") ;
  875.     exit (1) ;
  876.   }
  877.   if ((code_fragments = calloc (sizeof (viewer_code_fragment), MAX_FRAGMENT)) == NULL)
  878.   {
  879.     printf ("cannot allocate memory for code fragments\r\n") ;
  880.     exit (1) ;
  881.   }
  882.   if ((page_buffer = calloc (VSIZE_X, VSIZE_Y)) == NULL)
  883.   {
  884.     printf ("cannot allocate memory for page buffer\r\n") ;
  885.     exit (1) ;
  886.   }
  887.   if ((attribute_buffer = calloc (VSIZE_X, VSIZE_Y)) == NULL)
  888.   {
  889.     printf ("cannot allocate memory for attribute buffer\r\n") ;
  890.     exit (1) ;
  891.   }
  892.   clear_page_buffer () ;
  893.   memcpy (blank, page_buffer, VSIZE_X) ;
  894.   if ((toc = malloc ((unsigned) header.table_of_contents_length)) == NULL)
  895.   {
  896.     printf ("cannot allocate memory for table of contents\r\n") ;
  897.     exit (1) ;
  898.   }
  899.   TOCsize = sizeof (TOC_entry) + header.sec_number_len + header.sec_title_len ;
  900.   if ((reference_index = malloc ((unsigned) header.reference_index_length)) == NULL)
  901.   {
  902.     printf ("cannot allocate memory for reference index\r\n") ;
  903.     exit (1) ;
  904.   }
  905.   fseek (inF, header.reference_index, SEEK_SET) ;
  906.   if (fread (reference_index, (unsigned) header.reference_index_length, 1, inF) == 0)
  907.   {
  908.     printf ("could not read reference index\r\n") ;
  909.     exit (1) ;
  910.   }
  911.   if ((title = calloc ((unsigned) header.title_length + 1, 1)) == NULL)
  912.   {
  913.     printf ("cannot allocate memory for title\r\n") ;
  914.     exit (1) ;
  915.   }
  916.   fseek (inF, header.title, SEEK_SET) ;
  917.   if (fread (title, (unsigned) header.title_length + 1, 1, inF) == 0)
  918.   {
  919.     printf ("could not read title\r\n") ;
  920.     exit (1) ;
  921.   }
  922.   title [(unsigned) header.title_length] = 0 ;
  923.   if (load_strings ())
  924.   {
  925.     printf ("could not load reference strings\r\n") ;
  926.     exit (1) ;
  927.   }
  928. }
  929.  
  930. unsigned main (unsigned argc, char *argv [])
  931. {
  932.   int                   number = -1 ;
  933.   int                   count = -1 ;
  934.   char                  *s1 = "HELP.PHE" ;
  935.   char                  *s2 = "" ;
  936.   char                  gotoSection [16] = "1.0" ;
  937.   char                  gotoTitle [80] = "" ;
  938.  
  939.   while (++argv, --argc)
  940.   {
  941.     if (**argv == '-' || **argv == '+')
  942.     {
  943.       switch (toupper ((*argv) [1]))
  944.       {
  945.         case 'I' :
  946.              s1 = *argv + 2 ;
  947.              break ;
  948.  
  949.         case 'O' :
  950.              s2 = *argv + 2 ;
  951.              break ;
  952.  
  953.         case 'W' :
  954.              wsize_x = min (75, atoi (*argv + 2)) ;
  955.              break ;
  956.  
  957.         case 'F' :
  958.              noFAQ = 0 ;
  959.              break ;
  960.  
  961.         case 'N' :
  962.              number = atoi (*argv + 2) ;
  963.              if (count == -1) count = 0 ;
  964.              break ;
  965.  
  966.         case 'S' :
  967.              strncpy (gotoSection, *argv + 2, 15) ;
  968.              if (count == -1) count = 0 ;
  969.              break ;
  970.  
  971.         case 'T' :
  972.              strncpy (gotoTitle, *argv + 2, 79) ;
  973.              if (count == -1) count = 0 ;
  974.              break ;
  975.  
  976.         case 'C' :
  977.              count = atoi (*argv + 2) ;
  978.              break ;
  979.  
  980.         case 'J' :
  981.              justifyOn = (*argv) [2] != '-' ;
  982.              break ;
  983.  
  984.         case '?' :
  985.         case 'H' :
  986.              printf ("\r\nPHE2TXT : POV-Help to Text\r\n\n") ;
  987.              printf ("-i    : set input file name (default HELP.PHE)\r\n") ;
  988.              printf ("-o    : set output file name (default stdout)\r\n") ;
  989.              printf ("-w    : set width for output (default 77 characters)\r\n") ;
  990.              printf ("-j[-] : justify ON (default), -j- to turn off\r\n") ;
  991.              printf ("-f    : include FAQ section (if present) in output (default omit)\r\n") ;
  992.              printf ("-sX.Y : start from section X.Y (default 1.0)\r\n") ;
  993.              printf ("-tABC : start from section with title ABC\r\n") ;
  994.              printf ("-nn   : start from the nth section (first = 0)\r\n") ;
  995.              printf ("-cn   : process 'n' sections (default all unless -s, -t or -n, where 'n' = 1)\r\n") ;
  996.              printf ("\r\n") ;
  997.              return (0) ;
  998.  
  999.         default :
  1000.              printf ("unknown option '%s'\r\n", *argv) ;
  1001.              return (1) ;
  1002.       }
  1003.     }
  1004.   }
  1005.  
  1006.   if ((inF = fopen (s1, "rb")) == NULL)
  1007.   {
  1008.     printf ("could not open input file '%s'\r\n", s1) ;
  1009.     printf ("use phe2txt -h for help\r\n") ;
  1010.     return (1) ;
  1011.   }
  1012.   if (*s2)
  1013.   {
  1014.     if ((outF = fopen (s2, "wt")) == NULL)
  1015.     {
  1016.       printf ("could not open output file '%s'\r\n", s2) ;
  1017.       printf ("use phe2txt -h for help\r\n") ;
  1018.       return (1) ;
  1019.     }
  1020.   }
  1021.   else
  1022.     outF = stdout ;
  1023.   if (fread (&header, sizeof (help_file_header), 1, inF) == 0)
  1024.   {
  1025.     printf ("could not read header\r\n") ;
  1026.     return (1) ;
  1027.   }
  1028.  
  1029.   if (memcmp (header.signature, "POV-Help", 8) != 0)
  1030.   {
  1031.     printf ("header ID failed consistency check\r\n") ;
  1032.     return (1) ;
  1033.   }
  1034.  
  1035.   if (header.reader_version > VERSION)
  1036.   {
  1037.     printf ("version error ! database is not compatible [needs version %d.%d of reader]\r\n",
  1038.              header.reader_version / 100, header.reader_version % 100) ;
  1039.     return (1) ;
  1040.   }
  1041.  
  1042.   init () ;
  1043.  
  1044.   fseek (inF, header.table_of_contents, SEEK_SET) ;
  1045.   if (fread (toc, (unsigned) header.table_of_contents_length, 1, inF) == 0)
  1046.   {
  1047.     printf ("could not read table of contents\r\n") ;
  1048.     return (1) ;
  1049.   }
  1050.  
  1051.   left_margin = 0 ;
  1052.   right_margin = wsize_x ;
  1053.   device_setup () ;
  1054.  
  1055.   if (*gotoTitle) number = findTitle (gotoTitle) ;
  1056.   if (*gotoSection) number = findSection (gotoSection) ;
  1057.  
  1058.   if (number == -1)
  1059.   {
  1060.     number = 0 ;
  1061.     count = header.appendix_count + header.section_count ;
  1062.   }
  1063.   else
  1064.     if (count == 0)
  1065.       count = 1 ;
  1066.  
  1067.   if (count == -1)
  1068.     count = header.appendix_count + header.section_count - number ;
  1069.  
  1070.   if (number + count > header.appendix_count + header.section_count)
  1071.     count = header.appendix_count + header.section_count - number ;
  1072.  
  1073.   display_contents () ;
  1074.  
  1075.   first_line = 0 ;
  1076.  
  1077.   while (count--)
  1078.   {
  1079.     section = get_section (&tc, number++) ;
  1080.     if (noFAQ && strstr (tc.title, "FREQUENTLY ASKED QUESTIONS") != NULL) break ;
  1081.     format_section (&tc, section) ;
  1082.     free (section) ;
  1083.   }
  1084.  
  1085.   clear_attributes () ;
  1086.   set_attribute () ;
  1087.   clear_references () ;
  1088.   clear_page_buffer () ;
  1089.  
  1090.   display_text (AUTHOR) ;
  1091.  
  1092.   farfree (reference_string_index) ;
  1093.   farfree (reference_strings) ;
  1094.   free (toc) ;
  1095.   free (page_buffer) ;
  1096.   free (attribute_buffer) ;
  1097.   free (code_fragments) ;
  1098.   free (references) ;
  1099.   free (title) ;
  1100.   fclose (inF) ;
  1101.   return (0) ;
  1102. }